package com.txc.cloud.auth.common.config;

import com.txc.cloud.auth.common.filter.AuthLoginFilter;
import com.txc.cloud.auth.common.filter.AuthorityFilter;
import com.txc.cloud.auth.common.security.AuthAccessDeniedHandler;
import com.txc.cloud.auth.common.security.AuthLogoutHandler;
import com.txc.cloud.auth.common.security.UnAuthEntryPoint;
import com.txc.common.utils.jwt.TokenManager;
import com.txc.common.utils.middleware.RedisUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * @ClassName: SecurityConfig
 * @Author: TXC
 * @Date: 2022-07-29 10:13
 **/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {
    @Resource
    private UnAuthEntryPoint unAuthEntryPoint;
    @Resource
    private UserDetailsService userDetailService;
    @Resource
    private AuthAccessDeniedHandler accessDeniedHandler;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private AuthorityFilter authorityFilter;
    @Resource
    private AuthLogoutHandler authLogoutHandler;
    @Resource
    private AuthenticationConfiguration authenticationConfiguration;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private TokenManager tokenManager;

    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                // 允许跨域访问
                .cors(e -> e.configure(http))
                .formLogin().disable()
                .authenticationManager(authenticationManager())
                // 不需要session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .logout(logout -> logout.logoutUrl("/logout").addLogoutHandler(authLogoutHandler))
                // 没有权限访问时默认的返回值
                .exceptionHandling(exception -> exception.accessDeniedHandler(accessDeniedHandler).authenticationEntryPoint(unAuthEntryPoint))
                .authorizeHttpRequests(httpRequest ->
                        httpRequest
                                // 放行接口
                                .regexMatchers(HttpMethod.OPTIONS, "/*").permitAll()
                                .antMatchers("/login").permitAll()
                                .anyRequest().authenticated()
                ).authenticationProvider(authenticationProvider())
                // 登录拦截器
                .addFilter(new AuthLoginFilter(tokenManager, redisUtils, authenticationManager()))
                // 权限拦截器
                .addFilterBefore(authorityFilter, UsernamePasswordAuthenticationFilter.class)
                .httpBasic();
        return http.build();
    }

    /**
     * 获得用户名和密码的方式
     */
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailService);
        provider.setPasswordEncoder(passwordEncoder);
        return provider;
    }

    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

}
